package com.haixinga.commbiz.commons.biz;

import com.haixinga.commbiz.commons.utils.RedisUtil;
import com.haixinga.commbiz.commons.constants.CS;
import com.haixinga.commbiz.commons.utils.PropKit;
import com.haixinga.commbiz.commons.vo.AbstractLoginUserVO;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @Author terrfly
 * @Date 2020/2/13 16:28
 * @Description token service
 **/
public class ITokenService {


    /**  仅保存token在缓存中 （不包含用户LIST）
     * 1. 一般用于游客登录（并且需要sessionKey放置在缓存中的情况）
     * **/
    public static void processTokenCacheSingle(AbstractLoginUserVO currentUserInfo, String iToken){

        currentUserInfo.setIToken(iToken);  //设置token信息

        //保存token 和 tokenList信息
        RedisUtil.set(iToken, currentUserInfo, CS.TOKEN_TIME);  //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息， 例如验证接口权限， 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数， 如果放置多个key会增加非顺序读取。

        //在当前request线程保存用户信息,  避免再次查询redis导致失效问题。
        RequestContextHolder.getRequestAttributes().setAttribute(CS.REQ_CONTEXT_KEY_USERINFO, currentUserInfo, RequestAttributes.SCOPE_REQUEST);
    }

    /** 处理token信息
     * 1. 如果不允许多用户则踢掉之前的所有用户信息
     * 2. 更新token 缓存时间信息
     * 3. 更新用户token列表
     * **/
    public static void processTokenCache(AbstractLoginUserVO currentUserInfo, String iToken){

        currentUserInfo.setIToken(iToken);  //设置token信息
        Integer currentUID = currentUserInfo.getUserId();

        //当前用户的所有登录token 集合
        List<String> iTokenList = (List) RedisUtil.getObject(CS.getCacheKeyTokenList(currentUID), List.class);
        if(iTokenList == null){
            iTokenList = new ArrayList<>();
        }

        if(!iTokenList.contains(iToken)){
            iTokenList.add(iToken);
        }

        if(!PropKit.isAllowMultiUser()){ //不允许多用户登录

            Iterator<String> iterator = iTokenList.iterator();
            while(iterator.hasNext()){
                String tokenItem = iterator.next();
                if(tokenItem != null && !tokenItem.equals(iToken)){  //清除token信息， 清除list集合中的元素
                    RedisUtil.del(tokenItem);
                    iterator.remove();
                }
            }
        }

        //保存token 和 tokenList信息
        RedisUtil.set(iToken, currentUserInfo, CS.TOKEN_TIME);  //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息， 例如验证接口权限， 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数， 如果放置多个key会增加非顺序读取。
        RedisUtil.set(CS.getCacheKeyTokenList(currentUID), iTokenList, CS.TOKEN_TIME); //缓存时间2小时，超时自动清除
        //当允许多用户登录时也保存tokenList信息：
        // 优点： 1. 可以查看该账号多少人同时在线; 2. 是否允许多人同时在线的配置可灵活切换， 当切换不允许时可将所有的全部踢掉。
        // 缺点： 多占用redis内存


        //在当前request线程保存用户信息,  避免再次查询redis导致失效问题。
        RequestContextHolder.getRequestAttributes().setAttribute(CS.REQ_CONTEXT_KEY_USERINFO, currentUserInfo, RequestAttributes.SCOPE_REQUEST);
    }


    /** 退出时，清除token信息 */
    public static void removeIToken(String iToken, Integer currentUID){

        //1. 清除token的信息
        RedisUtil.del(iToken);

        //2. 处理tokenList
        String iTokenListKey = CS.getCacheKeyTokenList(currentUID);

        if(!PropKit.isAllowMultiUser()) { //如果不允许多用户, 则直接删除登录用户列表
            RedisUtil.del(iTokenListKey);
            return ;
        }

        //以下为允许多用户的情况
        List<String> iTokenList = (List) RedisUtil.getObject(iTokenListKey, List.class);

        if(iTokenList == null){
            return;
        }

        if(iTokenList.size() <= 1){  //数据小于等于1 仅包含一个直接删除即可
            RedisUtil.del(iTokenListKey);
            return;
        }

        //清除list中的iToken信息， 并重新设置
        iTokenList.remove(iToken);
        RedisUtil.set(iTokenListKey, iTokenList, CS.TOKEN_TIME);

    }

    /**
     * 刷新数据
     * **/
    public static void refData(AbstractLoginUserVO currentUserInfo){

        //保存token 和 tokenList信息
        RedisUtil.set(currentUserInfo.getIToken(), currentUserInfo, CS.TOKEN_TIME);  //缓存时间2小时, 保存具体信息而只是uid, 因为很多场景需要得到信息， 例如验证接口权限， 每次请求都需要获取。 将信息封装在一起减少磁盘请求次数， 如果放置多个key会增加非顺序读取。

    }





}
